var VSHADER_SOURCE =
  ` attribute vec4 a_Position;
  attribute vec4 a_Color;
  uniform mat4 u_ViewMatrix;
  uniform mat4 u_ModelMatrix;
  uniform mat4 u_OrthMatrix;
  uniform mat4 u_PerspectiveMatrix;
  varying vec4 v_Color;
  void main(){
    gl_Position = u_PerspectiveMatrix * u_ModelMatrix  * a_Position;
    v_Color = a_Color;
  }
`;

// Fragment shader program
var FSHADER_SOURCE = `
  #ifdef GL_ES
  precision mediump float; 
  #endif
  varying vec4 v_Color;
  void main(){
    gl_FragColor = v_Color;
  }
`;

var canvas, gl;
var verticesArr, indicesArr, verticesBuf, indicesBuf, texture, texture2;
var n, VERFSIZE, INDFSIZE,
  a_Position,
  a_Color,
  u_ViewMatrix,
  u_ModelMatrix,
  viewMatrix,
  modelMatrix,
  perspectiveMatrix,
  u_OrthMatrix,
  u_PerspectiveMatrix,
  cameraParam,
  orthoParam,
  perspectiveParam;
var ang = 0,ang2 = 0;

function initEnv() {
  canvas = document.getElementById('example');
  gl = getWebGLContext(canvas);
  // Specify the color for clearing <canvas>
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.enable(gl.DEPTH_TEST);
  // Initialize shaders
  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log('Failed to intialize shaders.');
    return;
  }
}

function initVertices() {
  
  verticesArr = new Float32Array([
    1.0, 1.0, 1.0, 1.0, 1.0, 1.0, // v0 White
    -1.0, 1.0, 1.0, 1.0, 0.0, 1.0, // v1 Magenta
    -1.0, -1.0, 1.0, 1.0, 0.0, 0.0, // v2 Red
    1.0, -1.0, 1.0, 1.0, 1.0, 0.0, // v3 Yellow
    1.0, -1.0, -1.0, 0.0, 1.0, 0.0, // v4 Green
    1.0, 1.0, -1.0, 0.0, 1.0, 1.0, // v5 Cyan
    -1.0, 1.0, -1.0, 0.0, 0.0, 1.0, // v6 Blue
    -1.0, -1.0, -1.0, 0.0, 0.0, 0.0 // v7 Black
  ]);

  indicesArr = new Uint8Array([
    0, 1, 2, 0, 2, 3, // front
    0, 3, 4, 0, 4, 5, // right
    0, 5, 6, 0, 6, 1, // up
    1, 6, 7, 1, 7, 2, // left
    7, 4, 3, 7, 3, 2, // down
    4, 7, 6, 4, 6, 5 // back
  ]);

  cameraParam = {
    x: 3,
    y: 3,
    z: 7,
    atX: 0,
    atY: 0,
    atZ: 0,
    upX: 0,
    upY: 1,
    upZ: 0
  }

  orthoParam = {
    near: 0.1,
    far: 1
  }

  perspectiveParam = {
    near: 1,
    far: 100,
    fov: 30,
    aspect: canvas.width / canvas.height
  }
  n = indicesArr.length;
  verticesBuf = gl.createBuffer();
  indicesBuf = gl.createBuffer();

  VERFSIZE = verticesArr.BYTES_PER_ELEMENT;
  a_Position = gl.getAttribLocation(gl.program, "a_Position");
  a_Color = gl.getAttribLocation(gl.program, 'a_Color');
  u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
  u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
  u_OrthMatrix = gl.getUniformLocation(gl.program, 'u_OrthMatrix');
  u_PerspectiveMatrix = gl.getUniformLocation(gl.program, 'u_PerspectiveMatrix');
  viewMatrix = new Matrix4();
  modelMatrix = new Matrix4();
  orthMatrix = new Matrix4();
  perspectiveMatrix = new Matrix4();

  if (!verticesBuf || a_Position < 0 || a_Color < 0 || !u_ViewMatrix || !u_ModelMatrix) {
    console.log(`initVertices error`);
    return -1;
  }
  return n;
}

function initEvent() {
  document.body.addEventListener("keydown", function (event) {
    console.log("keydown", event.keyCode);
    switch (event.keyCode) {
      case 39:
        cameraParam.x += 0.1;
        break;
      case 37:
        cameraParam.x -= 0.1;
        break;
      case 38:
        cameraParam.y += 0.1;
        break;
      case 40:
        cameraParam.y -= 0.1;
        break;
      case 87:
        cameraParam.z -= 0.1;
        break;
      case 83:
        cameraParam.z += 0.1;
        break;
      case 49:
        orthoParam.near -= 0.1;
        perspectiveParam.near -= 0.1;
        break;
      case 50:
        orthoParam.near += 0.1;
        perspectiveParam.near += 0.1;
        break;
      case 51:
        orthoParam.far -= 0.1;
        perspectiveParam.far -= 0.1;
        break;
      case 52:
        orthoParam.far += 0.1;
        perspectiveParam.far += 0.1;
        break;
    }
  })
}

function setDataAndDraw() {
  modelMatrix.setRotate(ang, 1, 1, 1);
  gl.bindBuffer(gl.ARRAY_BUFFER, verticesBuf);
  gl.bufferData(gl.ARRAY_BUFFER, verticesArr, gl.STATIC_DRAW);

  gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, VERFSIZE * 6, 0);
  gl.enableVertexAttribArray(a_Position);

  gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, VERFSIZE * 6, VERFSIZE * 3);
  gl.enableVertexAttribArray(a_Color);

  perspectiveMatrix.setPerspective(perspectiveParam.fov, perspectiveParam.aspect, perspectiveParam.near, perspectiveParam.far);
  perspectiveMatrix.lookAt(
    cameraParam.x, cameraParam.y, cameraParam.z,
    cameraParam.atX, cameraParam.atY, cameraParam.atZ,
    cameraParam.upX, cameraParam.upY, cameraParam.upZ
  );
  // Set the view matrix
  gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
  gl.uniformMatrix4fv(u_OrthMatrix, false, orthMatrix.elements);
  gl.uniformMatrix4fv(u_PerspectiveMatrix, false, perspectiveMatrix.elements);

  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indicesBuf);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indicesArr,gl.STATIC_DRAW);

  // Clear <canvas>
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT,0);
  gl.drawElements(gl.TRIANGLES,n,gl.UNSIGNED_BYTE,0);
}

function animate() {
  ang = (ang + 2) % (360)
  ang2 = (ang2 + 1) % (360)
  setDataAndDraw();
  requestAnimationFrame(animate);
}

function init() {
  initEnv();
  initEvent();
  initVertices();
  setDataAndDraw();
  animate();
}

function main() {
  init();
}